/*-------------------------------------------------
*File name: RiverFederate.cu
*Author: Tran Van Hoang
*Date: 20-04-2015
*--------------------------------------------------*/

#include "RTI.hh"
#include <cstdlib>
#include <iostream>
#include <string>
#include <cassert>
#include "RiverFederate.h"
#include "view.h"
#include "cuda.h"
#include "federation.h"
#include "cellNetwork.h"
#include "imageprocessing.h"

//Classes
#define CLA_FOREST_NODE "ForestNode"
#define CLA_RIVER_NODE "RiverNode"
//Attributes
#define ATT_POSITION_X "PositionX"
#define ATT_POSITION_Y "PositionY"
#define ATT_DENSITY "Density"
#define ATT_STATE "State"
#define ATT_IMAGEEXTENTX "ImageExtentX"
#define ATT_IMAGEEXTENTY "ImageExtentY"

using std::string;

int main()
{
	// create and run the federate
	RiverFederate *riverFederate;
		
	riverFederate = new RiverFederate(RIVER_FEDERATE_NAME, FEDERATION_FILE_NAME);
	riverFederate->runFederate(FEDERATION_NAME);
	
	delete riverFederate;
	return 0;
}
//--------------------------------------------------------------------------------------------
/** Main simualation
**/
#include <unistd.h>
#include <cuda.h>
#include <Xlib.h>
#include "dataRiver.cu"
#include "networkRiver.cu"

#define WINDOW_TITLE "Cellular Automata with CUDA: River Federate"

const int NUMBER_CYCLE = FEDERATION_CYCLE;

const int nbCells = sizeof(Cells)/sizeof(CellArray);

//If the number of cells between network and data are different, chosing the smaller one 

int dataSize = ((nbCells > NODE_NUMBER_RIVER) ? NODE_NUMBER_RIVER : nbCells);

Colormap colormap;
Display *dsp;
Window win;
GC gc;
int plotSize;
unsigned long white, black;
NodeState *nowState_h, *nowState_d, *nextState_h, *nextState_d, *buffState_d;

void RiverFederate::simulating()
{
	int NSize, blockSize, nodeSize, channelSize, nodeStateSize;
	int *now_h, *next_h, *now_d, *next_d;
	canaux *channels_d;	

	curandState *devState_d;

	dim3 tpb(NODE_NUMBER_RIVER, 1, 1);

        cudaMalloc((curandState**)&devState_d, NODE_NUMBER_RIVER * sizeof(curandState));

	plotSize = 1;
	NSize = 256;
	blockSize = 512;
	nodeSize = NODE_NUMBER_RIVER * sizeof(int);
	channelSize = NODE_NUMBER_RIVER * sizeof(canaux);	
	nodeStateSize = NODE_NUMBER_RIVER * sizeof(NodeState);
	dsp = XOpenDisplay(NULL);
	if (dsp == NULL)
	{ 
		printf("\n### Cannot connect to server.\n");
		return;
	}
	colormap = DefaultColormap(dsp, 0);

	int screenNumber = DefaultScreen(dsp);
	white = WhitePixel(dsp, screenNumber);
	black = BlackPixel(dsp, screenNumber);	

	win = XCreateSimpleWindow(dsp,
				DefaultRootWindow(dsp),
				50, 50,// origin
				NSize*plotSize*3, NSize*plotSize*3,// size
				0, black,//border
				COLOR_BACKGROUND//background
	);

	XStoreName(dsp, win, WINDOW_TITLE);
	XMapWindow(dsp, win);
	
	gc = XCreateGC(dsp, win, 0, NULL);	
	
	long eventMask = StructureNotifyMask;
	XSelectInput(dsp, win, eventMask);
	XEvent evt;
	do
	{
		XNextEvent(dsp, &evt);
	}while(evt.type != MapNotify);	
		
	/***********/
	//Allocating memory to host variables
	now_h = (int*)malloc(nodeSize);
	next_h = (int*)malloc(nodeSize);
	nowState_h = (NodeState*) malloc(nodeStateSize);
	nextState_h = (NodeState*) malloc(nodeStateSize);
	
	//Allocating memory to device variable
	cudaMalloc((void**)&now_d, nodeSize);
	cudaMalloc((void**)&next_d, nodeSize);
	cudaMalloc((canaux**)&channels_d, channelSize);
	cudaMalloc((NodeState**)&nowState_d, nodeStateSize);
	cudaMalloc((NodeState**)&nextState_d, nodeStateSize);
	cudaMalloc((NodeState**)&buffState_d, nodeStateSize);
	//Initilizing state of the nodes
	///// New version: Pollution diffusion
	initState(nowState_h, NODE_NUMBER_RIVER);
	//cudaMemcpy(nowState_d, nowState_h, nodeStateSize, cudaMemcpyHostToDevice);
	cudaMemcpy(channels_d, channels_h, channelSize, cudaMemcpyHostToDevice);

	printf("\n-- Initilizating image...\n");

	int density;

	for (int j = 0; j < NODE_NUMBER_RIVER; j++)
	{
	     density = (int) (nowState_h[j].density * 100.0);
	     showCellDensity(Cells[j], dsp, colormap, win, gc, plotSize, density);
	}

	printf("\n-- Click on the window to continue!\n");

	eventMask = ButtonPressMask | ButtonReleaseMask;

	XSelectInput(dsp, win, eventMask);
	do{
		XNextEvent(dsp, &evt);
	}while(evt.type != ButtonRelease);
	
	NodeState *temp;

	printf("-- Simulation is running: %d cycles...\n", NUMBER_CYCLE);

	//8. Registering an object to update
	RTI::ObjectHandle objectHandle = rtiamb.registerObjectInstance(RiverNodeClassID, RIVER_FEDERATE_NAME);

	RTIfedTime nextStep;

	for (int i = 0; i < NUMBER_CYCLE; i++)
	{
	    for (int j = 0; j < NODE_NUMBER_RIVER; j++)
	    {
	     	density = (int) (nowState_h[j].density * 100.0);
	     	showCellDensity(Cells[j], dsp, colormap, win, gc, plotSize, density);
	    }

	    nextStep = this->timeAdvance(1.0);

	    ///Copying new state to GPU. This comes from other federates at previous step.
	    cudaMemcpy(nowState_d, nowState_h, nodeStateSize, cudaMemcpyHostToDevice);

	    stepState<<<(NODE_NUMBER_RIVER / blockSize) + 1, blockSize>>>(nowState_d, nextState_d, channels_d, NODE_NUMBER_RIVER, devState_d);

	    cudaMemcpy(nextState_h, nextState_d, nodeStateSize, cudaMemcpyDeviceToHost);

	    this->sendUpdate(nextState_h, Cells, nextStep, objectHandle, NODE_NUMBER_RIVER);
	    	    
	    printf("\n=> Step %d is finished!\n  Refreshing view ...\n", i + 1);
	
	    for (int j = 0; j < NODE_NUMBER_RIVER; j++)
	    {
		density = (int) (nextState_h[j].density * 100.0);
	    	showCellDensity(Cells[j], dsp, colormap, win, gc, plotSize, density);
	    }

	    //Preparing for the next step	
	    temp = nextState_h;
	    nextState_h = nowState_h;
	    nowState_h = temp;
	    
	    temp = nextState_d;
	    nextState_d = nowState_d;
	    nowState_d = temp;	    	    	    	    
	}
	
	printf("\nClick on window to exit!\n");

	eventMask = ButtonPressMask | ButtonReleaseMask;

	XSelectInput(dsp, win, eventMask);
	do{
		XNextEvent(dsp, &evt);
	}while(evt.type != ButtonRelease);
	

	//Releasing resources
	XDestroyWindow(dsp, win);
	XCloseDisplay(dsp);
		
	cudaFree(now_d);
	cudaFree(next_d);
	cudaFree(channels_d);
	cudaFree(nowState_d);
	cudaFree(nextState_d);
	cudaFree(buffState_d);
	cudaFree(devState_d);

	free(now_h);
	free(next_h);
	free(nowState_h);
	free(nextState_h);
}

//----------------------------------------------------------------------------
/**Constructor
**/
RiverFederate::RiverFederate(std::string federate_name, std::string fdd_name):
	rtiamb(),
	federateName(federate_name),
	fddName(fdd_name),
	handle(0),
	creator(false),
	nbTicks(0),
	regulating(false),
	constrained(false),
	notimestamp(false),
	localTime(0.0),
	TIME_STEP(1.0),
	joined(false)
{
}
//-----------------------------------------------------------------------------
/**Destructor
*/
RiverFederate::~RiverFederate()
	throw (RTI::FederateInternalError)
{
}
//-----------------------------------------------------------------------------
/* Main Simulation Method
**/

void RiverFederate::runFederate(std::string federation_name)
{
	int autostart = 0;
	federationName = federation_name;
	//1. Creating the RTIambassador
	////finished in another way
	//2. Creating and joining to the federation
	this->createFederation(federationName);
	this->joinFederation(federationName);
	//3. Initialiazing the handles
	this->getHandles();
	//4. Annoucing the sync point
	// Announce a sync point to get everyone on the same page. if the point
	// has already been registered, we'll get a callback saying it failed,
	// but we don't care about that, as long as someone registered it
	this->pause();
	// tell the RTI we are ready to move past the sync point and then wait
	// until the federation has synchronized on
	//5. Achieving the point and wait for synchronization
	this->synchronize(autostart);
	//7. Publishing and subscribing
	this->setTimeRegulation(true, true);
	this->publishAndSubscribe();
	//8. Registering an object to update
	//RTI::ObjectHandle objectHandle = rtiamb.registerObjectInstance(RiverNodeClassID, RIVER_FEDERATE_NAME);
	//9. Doing the main simulation loop
	this->simulating();
	//10. Deleting the object
	//rtiamb.deleteObjectInstance(objectHandle, NULL);
	//11. Resigning from the federation
	rtiamb.resignFederationExecution(RTI::NO_ACTION);
	printf("\n-- Resigned from Federation!\n");
	//12. Destroying the federation
	try{
		rtiamb.destroyFederationExecution(FEDERATION_NAME);
		printf("\n-- Federation %s was destroyed!\n", FEDERATION_NAME);
	}catch(RTI::FederationExecutionDoesNotExist e)
	{
	     printf("\n### No need to destroy federation %s, it doesn't exist!\n", FEDERATION_NAME);
	}catch(RTI::FederatesCurrentlyJoined ex)
	{
	     printf("\n### Federate still joined, can't destroy federation %s!\n", FEDERATION_NAME);
	}
	//13. Cleaning up
	
}
//-----------------------------------------------
/** timeAdvance request
**/
RTIfedTime RiverFederate::timeAdvance(RTIfedTime time_step)
{
	granted = false;

	try{
	    rtiamb.queryFederateTime(localTime);
	}catch(RTI::Exception& e)
	{
	      printf("\n### Exception requesting for federate local time");
	}

	try{
	   RTIfedTime time_at(localTime.getTime()+TIME_STEP.getTime());
	   printf("\n-- time_at: %.2f - localtime: %.2f - timestep: %.2f\n", 
			time_at.getTime(), ((RTIfedTime&)localTime).getTime(), ((RTIfedTime&)TIME_STEP).getTime());
	   granted = false;
	   rtiamb.timeAdvanceRequest(time_at);

	}catch(RTI::Exception& e)
	{
		printf("\n### Exception with timeAdvancerequest!\n");
	}

	while(!granted)
	{
	     try{
	     	tick();
	     }catch(RTI::Exception& e)
	     {
		printf("\n### Exception ticking the RTI!\n");		
	     }
	}

	RTIfedTime next_step(localTime + TIME_STEP);
	return next_step;
}
//---------------------------------------------------------------------------------------
/** Rigister object
*****/
RTI::ObjectHandle RiverFederate::registerObject()
{
	return rtiamb.registerObjectInstance(RiverNodeClassID);
}

//---------------------------------------------------------------------------------------
/** Getting the federate handle
*/
RTI::FederateHandle RiverFederate::getHandle() const
{
	return handle;
}
//---------------------------------------------------------------------------------------
/** This method will get all the relevant handle information from the RTIambassador
***/
void RiverFederate::getHandles()
{
	printf("\n-- Getting handles ...\n");
	//Getting classes
	RiverNodeClassID = rtiamb.getObjectClassHandle(CLA_RIVER_NODE);
	ForestNodeClassID = rtiamb.getObjectClassHandle(CLA_FOREST_NODE);
	printf("\n-- RiverNodeClassID = %d, ForestNodeClassID = %d\n", (int) RiverNodeClassID, (int) ForestNodeClassID);
	//Getting attributes
	AttrXID = rtiamb.getAttributeHandle(ATT_POSITION_X, RiverNodeClassID);
	AttrYID = rtiamb.getAttributeHandle(ATT_POSITION_Y, RiverNodeClassID);
	AttrDensityID = rtiamb.getAttributeHandle(ATT_DENSITY, RiverNodeClassID);
	AttrImageExtentXID = rtiamb.getAttributeHandle(ATT_IMAGEEXTENTX, RiverNodeClassID);
	AttrImageExtentYID = rtiamb.getAttributeHandle(ATT_IMAGEEXTENTY, RiverNodeClassID);

	ForestAttrXID = rtiamb.getAttributeHandle(ATT_POSITION_X, ForestNodeClassID);
	ForestAttrYID = rtiamb.getAttributeHandle(ATT_POSITION_Y, ForestNodeClassID);
	ForestAttrStateID = rtiamb.getAttributeHandle(ATT_STATE, ForestNodeClassID);
	ForestAttrImageExtentXID = rtiamb.getAttributeHandle(ATT_IMAGEEXTENTX, ForestNodeClassID);
	ForestAttrImageExtentYID = rtiamb.getAttributeHandle(ATT_IMAGEEXTENTY, ForestNodeClassID);

	printf("\n-- AttrXD = %d, AttrYID = %d, ForestAttrStateID = %d, AttrImageExtentXID = %d, AttrImageExtentYID = %d \n", 
		(int) AttrXID, (int) AttrYID, (int) ForestAttrStateID, (int) AttrImageExtentXID, (int) AttrImageExtentYID);
	
}
//-----------------------------------------------------------------------------------------
/** Blocking untils the user press enter
***/
void RiverFederate::waitForUser()
{
	printf("\n>>>>>>>>>> Press ENTER to continue <<<<<<<<<<\n");	
	getchar();
}
//-----------------------------------------------------------------------------------------
/** Synchronizing with other federates
****/
void RiverFederate::synchronize(int auto_start)
{	
	printf("\n-- Synchronizing ...\n");
	if (creator == true)
	{
	    if (auto_start == 0)
	    {	
		printf("\n>>>>>>>>>>>> Press ENTER to start execution <<<<<<<<<<<<<\n");
		getchar();
	    }
	    else
	    {
		while (auto_start >= 0)
		{
		      sleep(0);
		      printf("\r-- Autostart: %5d", auto_start);
		      fflush(stdout);
		      auto_start--;
		}
		printf("\n");
	    }
	    printf("\n-- Creator can resume execution ...\n");
	    while(paused == false)
	    {
		try{
		    printf("\n-- Not paused!\n");
		    tick();
		}
		catch(RTI::Exception &e)
		{
		     printf("\n** Exception: Ticking the RTI: %d\n", (int) &e);
		     throw;
		}
	    }
	    printf("\n-- Execution is paused!\n");
	    
	    try {
		rtiamb.synchronizationPointAchieved("Init");
		printf("\n-- Pause is achieved.\n");
	    }
	    catch(RTI::Exception &e)
	    {
	     	printf("\n** Exception: Achieving a synchronization point by creator: %d\n", (int) &e);
	    }

	    while (paused == true)
	    {
		try{
		    tick();
		}
		catch(RTI::Exception &e)
		{
		     printf("\n** Exception: Ticking the RTI: %d\n", (int) &e);
		     throw;
		}
	    }
	}
	else//Not creator
	{
	    if (auto_start != 0)
	    {
		printf("\n-- Ignoring autostart because this federate is not creator\n");
	    }

	    printf("\n-- Synchronizing ...\n");
	    
	    if (paused == false)
	    {
		printf("\n-- Federate is not paused: too early!\n");
		while(paused == false)
		{
		     try{
			tick();
		     }
		     catch(RTI::Exception &e)
		     {
			  printf("\n** Exception: Ticking the RTI: %d\n", (int) &e);
		     	  throw;
		     }
		}
	    }
	    printf("\n-- Federate is paused.\n");
	    try {
		rtiamb.synchronizationPointAchieved("Init");
		printf("\n-- Pause is achieved.\n");
	    }
	    catch(RTI::Exception &e)
	    {
	     	printf("\n** Exception: Achieving a synchronization point by creator: %d\n", (int) &e);
	    }
	    printf("\n-- Federation is waiting until ending the pause ...\n");
	    while(paused == true)
	    {
		try{
		   tick();
		}
		catch(RTI::Exception &e)
		{ 
		       printf("\n** Exception: Ticking the RTI: %d\n", (int) &e);
		       throw;
		}
	    }	
	    printf("\n-- End of pause.\n");
	}
	printf("\n-- Federation is synchronized.\n");
}
//------------------------------------------------
/**This method try to create a new federation in the case of no federation. Ortherwise, 
**/
void RiverFederate::createFederation(std::string federation_name)
{
	try{
	   rtiamb.createFederationExecution(federation_name.c_str(), fddName.c_str());
	   printf("\n-- Federation execution named %s is created!\n", federation_name.c_str());
	   creator = true;
	}
	catch (RTI::FederationExecutionAlreadyExists &e){
	   printf("-- Exception: %s Reason is: %s. OK I can join it\n", e._name, e._reason);
	}
	catch (RTI::CouldNotOpenFED &e){
	   printf("** Federate %s : ERROR: %s Reason is: %s\n", federateName.c_str(), e._name, e._reason);
	   delete &rtiamb;
	   exit(0);
	}

}
//------------------------------------------------
/**It will join to the existing federation in case of the unjoined state.
*@federation_name: name of federation.
*
**/
void RiverFederate::joinFederation(std::string federation_name)
{
	//Joining the federation
	
	if (joined == false)
	{
	   try{
		handle = rtiamb.joinFederationExecution(federateName.c_str(), federation_name.c_str(), this);
		joined = true;		
		printf("-- Federate %s was joined to federation named %s!\n", federateName.c_str(), federation_name.c_str());
	   }
	   catch (RTI::FederateAlreadyExecutionMember &e){
		printf("## Exception: Federate %s already exists!\n", federateName.c_str());
		throw;
	   }
	   catch (RTI::FederationExecutionDoesNotExist &e){
		printf("** Exception: Federate %s : FederationExecutionDoesNotExists! \n", federateName.c_str());
	   }
	   catch (RTI::Exception &e){
		printf("** Federate %s : Join Federation Execution failed!\n", federateName.c_str());
	   }
	}
	
}

//-------------------------------------------------------------------------
/**This method allow creator to put federation in pause!
***/

void RiverFederate::pause()
{
	if (creator == true)
	{
	   printf("\n-- Pause requested.\n");
	   try{
		rtiamb.registerFederationSynchronizationPoint("Init", "-- Waiting for all federates ... \n");
		// Wait for user to kick us off
	   }
	   catch(RTI::Exception &e){
		printf("## Federate %s : Register Synchronization Point failed!\n", federateName.c_str());
	   }
	}
}

//---------------------------------------------------------------------
/** Ticking the RTI
**/
void RiverFederate::tick()
{
	printf("\r-- Tick...");
	rtiamb.tick();
	nbTicks++;
}

void RiverFederate::publishAndSubscribe()
{
	//Get all calss and attributes handles
	
	RTI::AttributeHandleSet *attributes = RTI::AttributeHandleSetFactory::create(5);
	attributes->add(AttrXID);
	attributes->add(AttrYID);
	attributes->add(AttrDensityID);
	attributes->add(AttrImageExtentXID);
	attributes->add(AttrImageExtentYID);
	
	//Pulishing Node objects
	printf("\n-- Publishing: class %d, attribute %d, %d, %d, %d and %d ...\n", 
		(int) RiverNodeClassID, (int) AttrXID, (int) AttrYID, (int) AttrDensityID, (int) AttrImageExtentXID, (int) AttrImageExtentYID);
	rtiamb.publishObjectClass(RiverNodeClassID, *attributes);
	printf("\n-- Publishing done.\n");

	//Subcribing to Node objects
	attributes = RTI::AttributeHandleSetFactory::create(5);
	attributes->add(ForestAttrXID);
	attributes->add(ForestAttrYID);
	attributes->add(ForestAttrStateID);
	attributes->add(ForestAttrImageExtentXID);
	attributes->add(ForestAttrImageExtentYID);

	rtiamb.subscribeObjectClassAttributes(ForestNodeClassID, *attributes, RTI::RTI_TRUE);
	printf("\n-- Subscribing done!\n");

}

void RiverFederate::setTimeRegulation(bool start_constrained, bool start_regulating)
{
        printf("\n-- Time Regulation setup ...\n");

        if (start_constrained == true)
        {
           if (!constrained)
           {
                rtiamb.enableTimeConstrained();
                constrained = true;
                printf("\n-- Time Constrained enabled.\n");
           }
        }
        else
        {
            if (constrained)
            {
                rtiamb.disableTimeConstrained();
                constrained = false;
                printf("\n-- Time Constrained disabled.\n");
            }
        }

        if (start_regulating == true)
        {
           if (!regulating)
           {
                for (;;)
                {
                    rtiamb.queryFederateTime(localTime);
                    try {
                        rtiamb.enableTimeRegulation(localTime, TIME_STEP);
                        regulating = true;
                        break;
                    }catch(RTI::FederationTimeAlreadyPassed)
                    {
                        rtiamb.queryFederateTime(localTime);
                        RTIfedTime requestTime(((RTIfedTime&)localTime).getTime());
                        requestTime += TIME_STEP;

                        granted = false;
                        while(!granted)
                        {
                             try{
                                tick();
                             }catch(RTI::RTIinternalError)
                             {
                                printf("\n-- RTIinternalError Raised in tick.\n");
                                exit(-1);
                             }
                        }
                    }catch(RTI::RTIinternalError)
                    {
                        printf("\n-- RTIinternalError Raised in setTimeRegulating.\n");
                        exit(-1);
                    }
                }
           }
        }
        else
        {
            if (regulating)
            {
                rtiamb.disableTimeRegulation();
                regulating = false;
            }
        }
}

void RiverFederate::checkRegions()
{

}

void RiverFederate::sendInteraction(double dx, double dy, const RTI::FedTime& InteractionTime, RTI::ObjectHandle id)
{
}

void RiverFederate::sendInteraction(double, double, RTI::ObjectHandle)
{
	
}

void RiverFederate::sendUpdate(NodeState *next_state_h, CellArray *cells, const RTI::FedTime & UpdateTime, RTI::ObjectHandle id, int node_number)
{
	float threshold = 0.0;
	libhla::MessageBuffer buffer;
	RTI::AttributeHandleValuePairSet *attributeSet;
	char tag[] = RIVER_FEDERATE_NAME;
	int nbAttribute = 5;
	attributeSet = RTI::AttributeSetFactory::create(node_number * nbAttribute);

	printf("\n-- Sending update class ID %d !\n", (int)id);

	int x, y, imgExtentWidth, imgExtentHeight;
	int density;

	for (int i = 0; i < node_number; i++)
	{
	    
	    x = cells[i].position.x;
	    y = cells[i].position.y;
	    imgExtentWidth = cells[i].image.extent.width;
	    imgExtentHeight = cells[i].image.extent.height;
	    density = next_state_h[i].density;

	    if (density > threshold)
	    {
	    	buffer.reset();
	    	buffer.write_int32(x);
	    	buffer.updateReservedBytes();
	    	attributeSet->add(AttrXID, static_cast<char*>(buffer(0)),buffer.size());

	    	buffer.reset();
	    	buffer.write_int32(y);
	    	buffer.updateReservedBytes();
	    	attributeSet->add(AttrYID, static_cast<char*>(buffer(0)),buffer.size());

	    	buffer.reset();
	    	buffer.write_int32(imgExtentWidth);
	    	buffer.updateReservedBytes();
	    	attributeSet->add(AttrImageExtentXID, static_cast<char*>(buffer(0)),buffer.size());

	    	buffer.reset();
	    	buffer.write_int32(imgExtentHeight);
	    	buffer.updateReservedBytes();
	    	attributeSet->add(AttrImageExtentYID, static_cast<char*>(buffer(0)),buffer.size());

	    	buffer.reset();
	    	buffer.write_double(density);
	    	buffer.updateReservedBytes();
	    	attributeSet->add(AttrDensityID, static_cast<char*>(buffer(0)),buffer.size());
	    }
	}

	try{
		if (notimestamp == true)
		{
		   rtiamb.updateAttributeValues(id, *attributeSet, tag);
		}else
		{
		   rtiamb.updateAttributeValues(id, *attributeSet, UpdateTime, tag);
		}
	}catch(RTI::Exception& e){
		printf("\n## Exception: %s (%s)\n",e._name, e._reason);
		delete attributeSet;
	}

	printf("\n-- Sending update finished!\n");

	delete attributeSet;
}

//============================================================================
// FEDERATE AMBASSDOR CALLBACKS
//============================================================================
///////////////////////////////////////////////////////////////////////////////
/////////////////////// Synchronization Point Callbacks ///////////////////////
///////////////////////////////////////////////////////////////////////////////
void RiverFederate::synchronizationPointRegistrationSucceeded(const char* label)
	throw(RTI::FederateInternalError)
{
	printf("\n-- Successfully registered sync point: %s\n", label);
}

void RiverFederate::synchronizationPointRegistrationFailed(const char* label)
	throw(RTI::FederateInternalError)
{
	printf("\n-- Failed to register sync point: %s\n", label);
}

void RiverFederate::announceSynchronizationPoint(const char *label, const char */*tag*/)
    throw (RTI::FederateInternalError)
{
	if (strcmp(label, "Init") == 0)
	{
	    printf("\n-- Synchronization point announced: %s\n", label);
	    paused = true;
	}
}

void RiverFederate::federationSynchronized(const char *label)
	throw(RTI::FederateInternalError)
{
	if (strcmp(label, "Init") == 0)
	{
	   printf("\n-- Federation Synchronized: %s\n", label);
	   paused = false;
	}
}

// ----------------------------------------------------------------------------
/** Callback : discover object instance
 */
void
RiverFederate::discoverObjectInstance(RTI::ObjectHandle theObject,
				RTI::ObjectClassHandle theObjectClass,
				const char */*theObjectName*/)
    throw (RTI::CouldNotDiscover, RTI::ObjectClassNotKnown, 
	   RTI::FederateInternalError)
{
	printf("\n-- discoverObjectInstance\n");
}

//-------------------------------------------------------------------------------
/** Callback: receive interaction
****/
void RiverFederate::receiveInteraction(RTI::InteractionClassHandle theInteraction,
                            const RTI::ParameterHandleValuePairSet & theParameters,
			    const RTI::FedTime& /*theTime*/,
                            const char */*theTag*/,
			    RTI::EventRetractionHandle /*theHandle*/)
        		throw ( RTI::InteractionClassNotKnown, 
				RTI::InteractionParameterNotKnown,
				RTI::InvalidFederationTime,
               			RTI::FederateInternalError)
{
}

void RiverFederate::reflectAttributeValues(RTI::ObjectHandle theObject,
                                const RTI::AttributeHandleValuePairSet& theAttributes,
                                const RTI::FedTime& theTime, 
				const char *theTag,
                                RTI::EventRetractionHandle theHandle)
        		throw (RTI::ObjectNotKnown, RTI::AttributeNotKnown,
               			RTI::InvalidFederationTime, RTI::FederateInternalError)
{
	libhla::MessageBuffer buffer;

	printf("\n-- Reflect attribute values with time: object=%d, tag=%s, time=%.2f", 
			(int)theObject, theTag, convertTime(theTime));

	int nbAttributes = 0;
	nbAttributes = theAttributes.size();

	printf("\n-- Number of attributes: %d \n", nbAttributes);

	int x, y, state, width, height;
	float distance;

	RTI::ULong i, length;

	if (strcmp(theTag, FOREST_FEDERATE_NAME) == 0)
	{
	   for (i = 0; i < nbAttributes; i++)
	   {
	   	RTI::AttributeHandle attHandle = theAttributes.getHandle(i);
	    	length = theAttributes.getValueLength(i);
	    	buffer.resize(length);
	    	buffer.reset();
	    	theAttributes.getValue(i, static_cast<char*>(buffer(0)), length);
	    	buffer.assumeSizeFromReservedBytes();
	    
	    	if (attHandle == ForestAttrXID)
	    	{
		   x = buffer.read_int32();
	    	}else if (attHandle == ForestAttrYID)
	    	{	
		   y = buffer.read_int32();
	    	}else if (attHandle == ForestAttrImageExtentXID)
	    	{	
		   width = buffer.read_int32();
	    	}else if (attHandle == ForestAttrImageExtentYID)
	    	{	
		   height = buffer.read_int32();
	    	}else if (attHandle == ForestAttrStateID)
	    	{
		   state = buffer.read_int32();
		   ///Displaying received data on window
		   CellArray cell;
		   cell.position.x = x;
		   cell.position.y = y;	
		   cell.image.extent.width = width;
		   cell.image.extent.height = height;

		   if (state == FIRED)
		   {
	     	       	//showCellForest(cell, dsp, colormap, win, gc, plotSize, COLOR_FIRED);
		   }else if (state == ASH)
		   {
		       	//showCellForest(cell, dsp, colormap, win, gc, plotSize, COLOR_ASH);
		       	//Finding the adjacent points between two physical systems according a certain threshold (THRESHOLD_FOREST_RIVER).
			for (int i = 0; i < NODE_NUMBER_RIVER; i++)
			{
			    distance = computeDistance(cell.position, Cells[i].position);
			    if (distance <= THRESHOLD_FOREST_RIVER)
			    {
				//Compute density in the river depending on the ash recieved from the forest fire.
				nowState_h[i].density += convertingASHToDensity(distance);
				//showCell(Cells[i], dsp, colormap, win, gc, plotSize, COLOR_ASH);
				//printf("\n*** Exchanging (Forest->River): (%d,%d) -> (%d,%d) : with distance = %.2f\n", 
				//	cell.position.x, cell.position.y, Cells[i].position.x, Cells[i].position.y, distance);
			    }
			}			
		   }
		
	    	}else
	    	   printf("\n-- Handle unkown\n");
	   }
	}
}

void RiverFederate::reflectAttributeValues(RTI::ObjectHandle theObject,
                                const RTI::AttributeHandleValuePairSet & theAttributes,
                                const char *theTag)
       	 		throw (RTI::ObjectNotKnown, RTI::AttributeNotKnown,
               			RTI::FederateInternalError)
{
	printf("\n--reflectAttributeValues\n");
}

void RiverFederate::receiveInteraction(RTI::InteractionClassHandle,
                            const RTI::ParameterHandleValuePairSet &,
                            const char *)
        		throw (RTI::InteractionClassNotKnown, RTI::InteractionParameterNotKnown,
               			RTI::FederateInternalError)
{
	printf("\n--ReceiveInteraction\n");
}
void RiverFederate::removeObjectInstance(RTI::ObjectHandle theObject, const RTI::FedTime& theTime,
                              const char *theTag,
                              RTI::EventRetractionHandle theHandle)
        		throw (RTI::ObjectNotKnown, RTI::InvalidFederationTime, RTI::FederateInternalError)
{
	printf("\n--removeObjectInstance\n");
}

void RiverFederate::removeObjectInstance(RTI::ObjectHandle, const char *)
        		throw (RTI::ObjectNotKnown, RTI::FederateInternalError)
{

}

//-----------------------------------------------------------------------------------------
/** Callback time advanced granted
**/
void RiverFederate::timeAdvanceGrant(const RTI::FedTime& theTime)
	throw (RTI::FederateInternalError, RTI::TimeAdvanceWasNotInProgress,
               			RTI::InvalidFederationTime)
{
	granted = true;
	localTime = theTime;
	printf("\n-- Time advanced, local time is now %.2f.\n", localTime.getTime());
}

double RiverFederate::convertTime(const RTI::FedTime& theTime)
{
	RTIfedTime time = (RTIfedTime)theTime;
	return time.getTime();
}

